package com.linktrip.devicemanager.server;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.linktrip.devicemanager.dao.IDeviceDao;
import com.linktrip.devicemanager.entity.DeviceInfo;
import com.linktrip.devicemanager.task.UnlockTask;
import com.linktrip.devicemanager.util.CommandUtil;
import com.linktrip.devicemanager.util.DevicesListHelper;
import com.linktrip.devicemanager.util.ToolKits;
import com.linktrip.devicemanager.websocket.entity.DataStruct;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;

@Service(value = "deviceService")
public class DeviceService {

	Logger log = LoggerFactory.getLogger(DeviceService.class);

	@Autowired
	IDeviceDao dao;

	@Autowired
	SMSService smsService;

	ExecutorService executor = Executors.newFixedThreadPool(100);

	public boolean addDeviceInfo(DeviceInfo entity) {
		entity.setDevice_no(entity.getDevice_no().toLowerCase());
		return dao.add(entity);
	}
	public boolean saveBatch(List<DeviceInfo> list){
		return dao.batchSave(list);
	}

	public boolean updateDeviceInfo(DeviceInfo entity) {
		return dao.update(entity);
	}
	
	public boolean updateDevice(DeviceInfo entity){
		log.info("service updateDevice.....no:{} timestamp:{}",entity.getDevice_no(),entity.getUpdate_date());
		return dao.updateDevice(entity) > 0;
	}

	public List<DeviceInfo> listDeviceInfo() {
		return dao.getList();
	}

	@SuppressWarnings("rawtypes")
	public List<DeviceInfo> listDeviceInfoPaging(Map map) {
		return dao.paging(map);
	}
	
	@SuppressWarnings("rawtypes")
	public int totals(Map map){
		return dao.totals(map);
	}

	public boolean removeDeviceInfo(DeviceInfo entity) {
		return dao.remove(entity);
	}

	public DeviceInfo getDeviceInfoById(int id) {
		return dao.getEntityById(id);
	}

	public List<String> matchingDeviceNo(String no) {
		return dao.matchingDeviceNo(no);
	}

	public DeviceInfo getDeviceInfoByDeviceNo(String no) {
		return dao.getEntityByNo(no);
	}

	public DeviceInfo getDeviceInfoByPhoneNumber(String number) {
		return dao.getDeviceInfoByPhoneNumber(number);
	}

	// UNLOCK BY SMS
	public DeviceInfo unLockDeviceBySMS(final DeviceInfo device, String content)
			throws InterruptedException, ExecutionException {
		log.info("unLockDeviceBySMS===>deviceNo:{} begin", device.getDevice_no());
		boolean reply = smsService.sendMsg(content, device.getPhone_number());
		if (reply == false) {
			device.setStatus(0);
			return device;
		}

		int status = 0;
		UnlockTask unlockTask = new UnlockTask(device.getDevice_no());
		FutureTask<Integer> future = new FutureTask<Integer>(unlockTask);
		executor.submit(future);
		// executor.shutdown();
		status = future.get(); // 任务处理结果获取
		device.setStatus(status);
		log.info("unLockDeviceBySMS===>deviceNo:{} status:{} end", device.getDevice_no(), status);
		return device;
	}

	// UNLOCK BY GPRS
	public DeviceInfo unLockDeviceByGPRS(final DeviceInfo device, DataStruct command)
			throws ExecutionException, InterruptedException {
		int status = 0;
		//short seq = (short) command.getMessageId();
		log.info("unLockDeviceByGPRS===>deviceNo:{} begin", device.getDevice_no());
		ChannelHandlerContext ctx = ToolKits.getDeviceSocketsMap_nio().get(device.getDevice_no());

		if (ctx == null || ctx.isRemoved()) {
			// 设备未与服务器保持长连接 发送短信
			log.info("refreshDevice socket is null or isClosed...");
			ToolKits.removeDeviceFromList(device.getDevice_no());
			device.setStatus(status);
			return device;
		}

		CommandUtil.sendCommand(ctx, command.toByteArray());
		UnlockTask unlockTask = new UnlockTask(device.getDevice_no());
		FutureTask<Integer> future = new FutureTask<Integer>(unlockTask);
		executor.submit(future);
		status = future.get(); // 任务处理结果获取
		device.setStatus(status);
		log.info("unLockDeviceByGPRS===>deviceNo:{} status:{} end", device.getDevice_no(), status);
		return device;
	}

	// UNLOCK BY GPRS AND SMS
	public DeviceInfo unLockDeviceByGPRSOrSMS(final DeviceInfo device, DataStruct command)
			throws ExecutionException, InterruptedException {
		int status = 0;
		//short seq = (short) command.getMessageId();
		log.info("unLockDeviceByGPRSAndSMS===>deviceNo:{} begin", device.getDevice_no());
		ChannelHandlerContext ctx = ToolKits.getDeviceSocketsMap_nio().get(device.getDevice_no());
		String content = CommandUtil.getUnlockCommand();

		if ((ctx == null || ctx.isRemoved())) {
			// 短信和长连接都不通
			log.info("deviceNo:{} socket is null or isClosed... send SMS",device.getDevice_no());
			ToolKits.removeDeviceFromList(device.getDevice_no());
			boolean reply = smsService.sendMsg(content, device.getPhone_number());
			
			if (!reply) {
				log.warn("sms reply:{}  短信下发失败 不通 不通......", reply);
				device.setStatus(status);
				return device;
			}

		} else {
			CommandUtil.sendCommand(ctx, command.toByteArray());
		}

		UnlockTask unlockTask = new UnlockTask(device.getDevice_no());
		FutureTask<Integer> future = new FutureTask<Integer>(unlockTask);
		executor.submit(future);
		status = future.get(); // 任务处理结果获取
		device.setStatus(status);
		log.info("unLockDeviceByGPRSAndSMS===>deviceNo:{} status:{} end", device.getDevice_no(), status);
		return device;
	}

	public DeviceInfo refreshDevice(DeviceInfo device) throws IOException {
		log.debug("refreshDevice action deviceId:{}", device.getDevice_no());
		ChannelHandlerContext ctx = ToolKits.getDeviceSocketsMap_nio().get(device.getDevice_no());
		if (ctx == null || ctx.isRemoved()) {
			// 设备未与服务器保持长连接 发送短信
			log.debug("refreshDevice socket is null or isClosed...");
			ToolKits.removeDeviceFromList(device.getDevice_no());
			return null;
		}

		byte[] data = DevicesListHelper.CMD_REQUEST;
		ByteBuf bf = Unpooled.buffer(data.length);
		bf.writeBytes(data);
		ctx.writeAndFlush(bf);
		log.debug("SEND REFRESH COMMAND...");
		return null;
	}
}
